//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_Script.h".
//-------------------------------------------------------------------

#include "DefaultBindings.h"

namespace UX_STL
{
namespace UXScript
{
	
	namespace _def_bindings_hidden_
	{
		using namespace UXMath;
		

		
		template <typename T>
		struct InitVecFields
		{
			static void Init (ClassBinder<T> &binder)
			{
				STATIC_WARNING( "not supported" );
			}
		};


		template <typename T>
		struct BaseVecCtors
		{
			static void Ctor1 (void *mem, typename T::value_t value)
			{
				new( mem ) T( value );
			}
			
			static void Ctor2 (void *mem, TVec< typename T::value_t, 2 > value)
			{
				new( mem ) T( value );
			}
			
			static void Ctor3 (void *mem, TVec< typename T::value_t, 3 > value)
			{
				new( mem ) T( value );
			}
			
			static void Ctor4 (void *mem, TVec< typename T::value_t, 4 > value)
			{
				new( mem ) T( value );
			}
		};

		
		template <typename T>
		struct InitVecFields< TVec< T, 2 > > : BaseVecCtors< TVec< T, 2 > >
		{
			static void CtorArg2 (void *mem, T x, T y)
			{
				new( mem ) TVec<T,2>( x, y );
			}
			
			static void Init (ClassBinder< TVec< T, 2 > > &binder)
			{
				typedef TVec< T, 2 >	vec_t;
				typedef T				value_t;

				binder.AddProperty( &vec_t::x, "x" );
				binder.AddProperty( &vec_t::y, "y" );

				binder.AddConstructor( &Ctor1 );
				binder.AddConstructor( &Ctor3 );
				binder.AddConstructor( &Ctor4 );
				binder.AddConstructor( &CtorArg2 );
			}
		};

		
		template <typename T>
		struct InitVecFields< TVec< T, 3 > > : BaseVecCtors< TVec< T, 3 > >
		{
			static void CtorArg2 (void *mem, const TVec<T,2> &xy, T z)
			{
				new( mem ) TVec<T,3>( xy, z );
			}

			static void CtorArg3 (void *mem, T x, T y, T z)
			{
				new( mem ) TVec<T,3>( x, y, z );
			}

			static void Init (ClassBinder< TVec< T, 3 > > &binder)
			{
				typedef TVec< T, 3 >	vec_t;
				typedef T				value_t;

				binder.AddProperty( &vec_t::x, "x" );
				binder.AddProperty( &vec_t::y, "y" );
				binder.AddProperty( &vec_t::z, "z" );

				binder.AddConstructor( &Ctor1 );
				binder.AddConstructor( &Ctor2 );
				binder.AddConstructor( &Ctor4 );
				binder.AddConstructor( &CtorArg2 );
				binder.AddConstructor( &CtorArg3 );
			}
		};

		
		template <typename T>
		struct InitVecFields< TVec< T, 4 > > : BaseVecCtors< TVec< T, 4 > >
		{
			static void CtorArg2 (void *mem, const TVec<T,2> &xy, const TVec<T,2> &zw)
			{
				new( mem ) TVec<T,4>( xy, zw );
			}
			
			static void CtorArg3 (void *mem, const TVec<T,3> &xyz, T w)
			{
				new( mem ) TVec<T,4>( xyz, w );
			}

			static void CtorArg4 (void *mem, T x, T y, T z, T w)
			{
				new( mem ) TVec<T,4>( x, y, z, w );
			}

			static void Init (ClassBinder< TVec< T, 4 > > &binder)
			{
				typedef TVec< T, 4 >	vec_t;
				typedef T				value_t;

				binder.AddProperty( &vec_t::x, "x" );
				binder.AddProperty( &vec_t::y, "y" );
				binder.AddProperty( &vec_t::z, "z" );
				binder.AddProperty( &vec_t::w, "w" );

				binder.AddConstructor( &Ctor1 );
				binder.AddConstructor( &Ctor2 );
				binder.AddConstructor( &Ctor3 );
				binder.AddConstructor( &CtorArg2 );
				binder.AddConstructor( &CtorArg3 );
				binder.AddConstructor( &CtorArg4 );
			}
		};


		template <typename T>
		void BindVecFloatOperators (ClassBinder<T> &binder)
		{
			typedef typename ClassBinder<T>::type	vec_t;
			typedef typename vec_t::value_t			value_t;
			
			binder.AddIncOperators();

			binder.AddUnaryMathOperators< const vec_t >();

			binder.AddBinaryMathOperators< const vec_t &, const vec_t >();
			binder.AddBinaryMathOperators< const value_t &, const vec_t >();

			binder.AddBinaryAssignmentMathOperators< const vec_t & >();
			binder.AddBinaryAssignmentMathOperators< const value_t & >();

			binder.AddBinaryRightMathOperators< const value_t&, const vec_t >();

			binder.AddIndexOperators< usize, value_t &, const value_t & >();
		}


		template <typename T>
		void BindVecIntegerOperators (ClassBinder<T> &binder)
		{
			typedef typename ClassBinder<T>::type	vec_t;
			typedef typename vec_t::value_t			value_t;

			BindVecFloatOperators( binder );
			
			binder.AddUnaryBitOperators< const vec_t >();
			
			binder.AddBinaryBitOperators< const vec_t &, const vec_t >();
			binder.AddBinaryBitOperators< const value_t &, const vec_t >();
			
			binder.AddBinaryBitShiftOperators< const vec_t &, const vec_t >();
			binder.AddBinaryBitShiftOperators< const value_t &, const vec_t >();

			binder.AddBinaryAssignmentBitOperators< const vec_t & >();
			binder.AddBinaryAssignmentBitOperators< const value_t & >();

			binder.AddBinaryAssignmentBitShiftOperators< const vec_t & >();
			binder.AddBinaryAssignmentBitShiftOperators< const value_t & >();
			
			binder.AddBinaryRightBitOperators< const value_t&, const vec_t >();
			binder.AddBinaryRightBitShiftOperators< const value_t&, const vec_t >();
		}
		
#		define _ADD_METHOD( _name ) \
			binder.AddMethod( &vec_t::_name, #_name )

		template <typename T>
		void BindVecFloatMethods (ClassBinder<T> &binder)
		{
			typedef typename ClassBinder<T>::type	vec_t;
			typedef typename vec_t::value_t			value_t;

			_ADD_METHOD( Length );
			_ADD_METHOD( LengthSqr );
			_ADD_METHOD( Normalized );
			_ADD_METHOD( Normalize );
			_ADD_METHOD( SetLength );
			_ADD_METHOD( Dot );
			_ADD_METHOD( DotAbs );
			_ADD_METHOD( Distance );
			_ADD_METHOD( DistanceSqr );
			_ADD_METHOD( InterpolateL );
			_ADD_METHOD( InterpolateQ );
			_ADD_METHOD( GetInterpolatedL );
			_ADD_METHOD( GetInterpolatedQ );
			_ADD_METHOD( Reflect );
			_ADD_METHOD( Refract );
			_ADD_METHOD( Sum );
			_ADD_METHOD( SumAbs );
			_ADD_METHOD( Area );
			_ADD_METHOD( Volume );
			_ADD_METHOD( Min );
			_ADD_METHOD( Max );
		}

		template <typename T>
		void BindVecIntMethods (ClassBinder<T> &binder)
		{
			typedef typename ClassBinder<T>::type	vec_t;
			typedef typename vec_t::value_t			value_t;

			_ADD_METHOD( Sum );
			_ADD_METHOD( SumAbs );
			_ADD_METHOD( Area );
			_ADD_METHOD( Volume );
			_ADD_METHOD( Min );
			_ADD_METHOD( Max );
		}

#		undef _ADD_METHOD


#		define _ADD_FUNC( _type, _name ) \
			se.AddFunction< _type >( &_name, #_name )

		template <typename T, uint8 I>
		static TVec<T,I> ModVec (const TVec<T,I> &left, const TVec<T,I> &right)
		{
			return UXMath::Mod<T,T,I>( left, right );
		}

		template <typename T>
		void BindScalarAndVecFloatFuncs (Ptr< AngelScript::asIScriptEngine > eng)
		{
			ScriptEngine	se( eng );

			_ADD_FUNC( T (*) (const T &),			DTR		);
			_ADD_FUNC( T (*) (const T &),			RTD		);
			_ADD_FUNC( T (*) (const T &),			Sin		);
			_ADD_FUNC( T (*) (const T &),			Cos		);
			_ADD_FUNC( T (*) (const T &),			ASin	);
			_ADD_FUNC( T (*) (const T &),			ACos	);
			_ADD_FUNC( T (*) (const T &),			SinH	);
			_ADD_FUNC( T (*) (const T &),			CosH	);
			_ADD_FUNC( T (*) (const T &),			ASinH	);
			_ADD_FUNC( T (*) (const T &),			ACosH	);
			_ADD_FUNC( T (*) (const T &),			Tan		);
			_ADD_FUNC( T (*) (const T &),			CoTan	);
			_ADD_FUNC( T (*) (const T &),			ATan	);

			_ADD_FUNC( T (*) (const T &, const T &),	ATan	);

			_ADD_FUNC( T (*) (const T &),			ACoTan	);
			_ADD_FUNC( T (*) (const T &),			ATanH	);
			_ADD_FUNC( T (*) (const T &),			ACoTanH );

			_ADD_FUNC( T (*) (const T &),			Abs		);
			_ADD_FUNC( T (*) (const T&, bool),		SetSign );
			_ADD_FUNC( T (*) (const T&, const T&),	CopySign );

			_ADD_FUNC( bool (*) (const T &),		All );
			_ADD_FUNC( bool (*) (const T &),		Any );
			_ADD_FUNC( bool (*) (const T &),		Most );
			_ADD_FUNC( bool (*) (const T &),		IsZero );
			_ADD_FUNC( bool (*) (const T &),		IsNotZero );
			
			_ADD_FUNC( T (*) (const T&, const T&),						Max );
			_ADD_FUNC( T (*) (const T&, const T&, const T&),			Max );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const T&),	Max );
			_ADD_FUNC( T (*) (const T&, const T&),						Min );
			_ADD_FUNC( T (*) (const T&, const T&, const T&),			Min );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const T&),	Min );
			_ADD_FUNC( T (*) (const T&, const T&),						MaxAbs );
			_ADD_FUNC( T (*) (const T&, const T&),						MinAbs );
			_ADD_FUNC( void (*) (T&, T&, const T&, const T&),			MinMax );

			_ADD_FUNC( T (*) (const T&, const T&, const T&),	Clamp );
			_ADD_FUNC( T (*) (const T&, const T&, const T&),	ClampOut );

			_ADD_FUNC( T (*) (const T&, const T&),	Pow );
			_ADD_FUNC( T (*) (const T&),			Ln );
			_ADD_FUNC( T (*) (const T&, const T&),	Log );
			_ADD_FUNC( T (*) (const T&),			Log2 );
			_ADD_FUNC( T (*) (const T&),			Log10 );
			_ADD_FUNC( T (*) (const T&),			Exp );
			_ADD_FUNC( T (*) (const T&),			Exp2 );
			_ADD_FUNC( T (*) (const T&),			Exp10 );

			_ADD_FUNC( T (*) (const T&),			Square );
			_ADD_FUNC( T (*) (const T&),			Sqrt );
			_ADD_FUNC( T (*) (const T&),			SquareSign );
			_ADD_FUNC( T (*) (const T&),			InvSqrt );
			
			_ADD_FUNC( T (*) (const T&),			Floor );
			_ADD_FUNC( T (*) (const T&),			Ceil );
			_ADD_FUNC( T (*) (const T&),			Fract );
			_ADD_FUNC( T (*) (const T&, const T&),	ModVec );

			_ADD_FUNC( T (*) (const T&, const T&, const T&),	SafeDiv );

		}
		

		template <typename T>
		void BindVecFloatFuncs (Ptr< AngelScript::asIScriptEngine > eng)
		{
			typedef typename T::value_t	V;
			enum { C = T::STATIC_COUNT };

			ScriptEngine	se( eng );

			typedef TVec<int,C>		ivec_t;
			typedef TVec<uint,C>	uvec_t;
			typedef TVec<bool,C>	bvec_t;
			
			typedef NearInt::Signed< V >::type	sint_t;
			typedef TVec< sint_t, C >			sivec_t;

			_ADD_FUNC( ivec_t (*) (const T&),		Sign );
			_ADD_FUNC( ivec_t (*) (const T&),		SignOrZero );
			
			_ADD_FUNC( bvec_t (*) (const T&, const T&),					Equals );
			_ADD_FUNC( bvec_t (*) (const T&, const T&, const uint&),	Equals );
			
			//_ADD_FUNC( T (*) (const ivec_t &),		Pow2 );
			//_ADD_FUNC( T (*) (const ivec_t &),		Pow10 );

			_ADD_FUNC( T (*) (const T&, const T&, const V&),			Mix );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const V&),	QMix );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const T&, const V&, const V&),	BiMix );

			//_ADD_FUNC( sivec_t (*) (const T&),			Round );

			BindScalarAndVecFloatFuncs<T>( eng );
		}
		

		template <typename T>
		void BindVecIntFuncs (Ptr< AngelScript::asIScriptEngine > eng)
		{
			typedef typename T::value_t	V;
			enum { C = T::STATIC_COUNT };

			ScriptEngine	se( eng );

			typedef TVec<int,C>		ivec_t;
			typedef TVec<uint,C>	uvec_t;
			typedef TVec<bool,C>	bvec_t;
			/*
			_ADD_FUNC( uvec_t (*) (const T&),	PowerOfTwo );
			_ADD_FUNC( uvec_t (*) (const T&),	CeilPowerOfTwo );
			_ADD_FUNC( uvec_t (*) (const T&),	FloorPowerOfTwo );
			_ADD_FUNC( uvec_t (*) (const T&),	NearPowerOfTwo );
			_ADD_FUNC( bvec_t (*) (const T&),	IsPowerOfTwo );*/
			/*
			_ADD_FUNC( T (*) (const ivec_t&),				ToBit );
			_ADD_FUNC( T (*) (const ivec_t&),				ARGS( ToMask<V,C,int> ) );
			_ADD_FUNC( T (*) (const T&),					GetMaskForType );
			_ADD_FUNC( T (*) (const T&, const ivec_t&),		SafeLeftBitShift );
			_ADD_FUNC( T (*) (const T&, const ivec_t&),		SafeRightBitShift );*/
			
			_ADD_FUNC( bvec_t (*) (const T&),			IsOdd );
			_ADD_FUNC( bvec_t (*) (const T&),			IsEven );
		}


		template <typename T>
		void BindScalarFloatFuncs (Ptr< AngelScript::asIScriptEngine > eng)
		{
			ScriptEngine	se( eng );

			_ADD_FUNC( T (*)(),						Pi );
			_ADD_FUNC( T (*)(),						Exp );
			_ADD_FUNC( T (*)(),						ReciporalPi );
			
			typedef TVec<T,2>	vec2_t;

			_ADD_FUNC( vec2_t (*)(const T &),		SinCos );
			_ADD_FUNC( vec2_t (*)(const T &),		ASinCos );
			_ADD_FUNC( vec2_t (*)(const T &),		SinCosH );
			_ADD_FUNC( vec2_t (*)(const T &),		ASinCosH );

			_ADD_FUNC( bool (*) (const T&, const T&),					Equals );
			_ADD_FUNC( bool (*) (const T&, const T&, const uint&),		Equals );
			
			_ADD_FUNC( T (*) (const int&),		Pow2 );
			_ADD_FUNC( T (*) (const int&),		Pow10 );
			
			_ADD_FUNC( uint (*) (const T&),		PowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		CeilPowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		FloorPowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		NearPowerOfTwo );
			_ADD_FUNC( bool (*) (const T&),		IsPowerOfTwo );
			
			_ADD_FUNC( T (*) (const T&, const T&, const T&),								Mix );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const T&),						QMix );
			_ADD_FUNC( T (*) (const T&, const T&, const T&, const T&, const T&, const T&),	BiMix );
			
			_ADD_FUNC( bool (*) (const T&),		IsNAN );
			_ADD_FUNC( bool (*) (const T&),		IsOdd );
			_ADD_FUNC( bool (*) (const T&),		IsEven );

			BindScalarAndVecFloatFuncs<T>( eng );
		}


		template <typename T>
		void BindScalarIntFuncs (Ptr< AngelScript::asIScriptEngine > eng)
		{
			ScriptEngine	se( eng );

			_ADD_FUNC( uint (*) (const T&),		PowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		CeilPowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		FloorPowerOfTwo );
			_ADD_FUNC( T	(*) (const T&),		NearPowerOfTwo );
			_ADD_FUNC( bool (*) (const T&),		IsPowerOfTwo );
		}

#		undef _ADD_FUNC


		// float
		template <bool IsFloat, bool isBool>
		struct VecSwitch
		{
			template <typename T>
			static void BindVec (ClassBinder<T> &binder)
			{
				BindVecFloatOperators( binder );
				BindVecFloatMethods( binder );
				BindVecFloatFuncs<T>( binder.GetEngine() );
			}
		};

		// int
		template <>
		struct VecSwitch <false, false>
		{
			template <typename T>
			static void BindVec (ClassBinder<T> &binder)
			{
				BindVecIntegerOperators( binder );
				BindVecIntMethods( binder );
				BindVecIntFuncs<T>( binder.GetEngine() );
			}
		};

		// bool
		template <>
		struct VecSwitch <false, true>
		{
			template <typename T>
			static void BindVec (ClassBinder<T> &binder)
			{
			}
		};


		template <typename T>
		void VecForwardDecl (AngelScript::asIScriptEngine *se)
		{
			ClassBinder<T>	binder( se );

			binder.CreateClassValue();
		}


		template <typename T>
		void BindVec (AngelScript::asIScriptEngine *se)
		{
			ClassBinder<T>	binder( se );

			InitVecFields<T>::Init( binder );

			VecSwitch< TypeDescriptor::IsFloat< typename T::value_t >::value,
						TypeDescriptor::IsSameTypes< typename T::value_t, bool >::value
					 >::BindVec( binder );
		}

	}	// _def_bindings_hidden_
	
/*
=================================================
	BindMath
=================================================
*/
	void DefaultBindings::BindMath (AngelScript::asIScriptEngine *se)
	{
	}
	
/*
=================================================
	BindVector
=================================================
*/
	void DefaultBindings::BindVector (AngelScript::asIScriptEngine *se)
	{
		_def_bindings_hidden_::VecForwardDecl< UXMath::bvec2 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::ivec2 >( se );
		//_def_bindings_hidden_::VecForwardDecl< UXMath::uvec2 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::lvec2 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::fvec2 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::dvec2 >( se );
		
		_def_bindings_hidden_::VecForwardDecl< UXMath::bvec3 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::ivec3 >( se );
		//_def_bindings_hidden_::VecForwardDecl< UXMath::uvec3 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::lvec3 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::fvec3 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::dvec3 >( se );
		
		_def_bindings_hidden_::VecForwardDecl< UXMath::bvec4 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::ivec4 >( se );
		//_def_bindings_hidden_::VecForwardDecl< UXMath::uvec4 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::lvec4 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::fvec4 >( se );
		_def_bindings_hidden_::VecForwardDecl< UXMath::dvec4 >( se );

		_def_bindings_hidden_::BindVec< UXMath::bvec2 >( se );
		_def_bindings_hidden_::BindVec< UXMath::ivec2 >( se );
		//_def_bindings_hidden_::BindVec< UXMath::uvec2 >( se );
		_def_bindings_hidden_::BindVec< UXMath::lvec2 >( se );
		_def_bindings_hidden_::BindVec< UXMath::fvec2 >( se );
		_def_bindings_hidden_::BindVec< UXMath::dvec2 >( se );
		
		_def_bindings_hidden_::BindVec< UXMath::bvec3 >( se );
		_def_bindings_hidden_::BindVec< UXMath::ivec3 >( se );
		//_def_bindings_hidden_::BindVec< UXMath::uvec3 >( se );
		_def_bindings_hidden_::BindVec< UXMath::lvec3 >( se );
		_def_bindings_hidden_::BindVec< UXMath::fvec3 >( se );
		_def_bindings_hidden_::BindVec< UXMath::dvec3 >( se );
		
		_def_bindings_hidden_::BindVec< UXMath::bvec4 >( se );
		_def_bindings_hidden_::BindVec< UXMath::ivec4 >( se );
		//_def_bindings_hidden_::BindVec< UXMath::uvec4 >( se );
		_def_bindings_hidden_::BindVec< UXMath::lvec4 >( se );
		_def_bindings_hidden_::BindVec< UXMath::fvec4 >( se );
		_def_bindings_hidden_::BindVec< UXMath::dvec4 >( se );
	}
	
/*
=================================================
	BindVectorMath
=================================================
*/
	void DefaultBindings::BindVectorMath (AngelScript::asIScriptEngine *se)
	{
	}
	
//-------------------------------------------------------------------

}	// UXScript
}	// UX_STL